package com.common;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;

import java.io.*;

@SuppressWarnings("all")
public class FTPUtil {

	Environment env;

	protected static final Logger logger = LoggerFactory.getLogger(FTPUtil.class);
	private static FTPUtil ftpUtils;
	private FTPClient ftpClient;

	private String serverUrl; // 服务器地址
	private int port; // 服务器端口
	private String username; // 用户登录名
	private String password; // 用户登录密码
	private InputStream is; // 文件下载输入流

	/**
	 * 私有构造方法
	 */
	private FTPUtil(Environment env) {
	    this.env = env;
		initConfig();
		if (null == ftpClient) {
			ftpClient = new FTPClient();
		}
	}
	/**
	 * 获取FTPUtils对象实例
	 * 
	 * @return FTPUtils对象实例
	 */
	public synchronized static FTPUtil getInstance(Environment env) {
		if (null == ftpUtils) {
			ftpUtils = new FTPUtil(env);
		}
		return ftpUtils;
	}

	/**
	 * 初始化FTP服务器连接属性
	 */
	public void initConfig() {
		this.serverUrl = env.getProperty("ftp.serverUrl");
		this.port = Integer.parseInt(env.getProperty("ftp.port"));
		this.username = env.getProperty("ftp.username");
		this.password = env.getProperty("ftp.password");
	}

	/**
	 * 连接（配置通用连接属性）至服务器
	 * 
	 * @param serverName
	 *            服务器名称
	 * @param remotePath
	 *            当前访问目录
	 * @return <b>true</b>：连接成功 <br/>
	 *         <b>false</b>：连接失败
	 */
	public boolean connect(String remotePath) {
		// 定义返回值
		boolean result = false;
		try {
			// 连接至服务器，端口默认为21时，可直接通过URL连接
			ftpClient.connect(serverUrl, port);
			// 登录服务器
			ftpClient.login(username, password);
			// 判断返回码是否合法
			if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
				// 不合法时断开连接
				ftpClient.disconnect();
				// 结束程序
				return result;
			}
			// 设置字符编码
			ftpClient.setControlEncoding("utf-8");
			FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
			conf.setServerLanguageCode("zh"); 
			// 设置文件传输模式
			// 被动模式
			// ftpClient.enterLocalPassiveMode();
			// 创建目录  设置文件操作目录
			createDir(remotePath);
			// 设置文件类型，二进制
			result = ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			// 设置缓冲区大小
			ftpClient.setBufferSize(2048);

		} catch (IOException e) {
			logger.error("连接FTP服务器异常", e);
			throw new RuntimeException("连接FTP服务器异常", e);
		}
		return result;
	}
	
	/**
	 * 创建目录
	 * @param path
	 * @return
	 */
	public boolean createDir(String path) {
		boolean flag = false;
        if (path != null && !"".equals(path.trim())) {
            String[] pathes = path.split("/");
            for (String onepath : pathes) {
                if (onepath == null || "".equals(onepath.trim())) {
                    continue;
                }
                try {
                	onepath = new String(onepath.getBytes(), ftpClient.getControlEncoding());
					if (!ftpClient.changeWorkingDirectory(onepath)) {
					    ftpClient.makeDirectory(onepath);
					    flag = ftpClient.changeWorkingDirectory(onepath);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
            }
        } else {
        	flag = false;
        }
        return flag;
	}
	
	/**
	 * 上传文件至FTP服务器
	 * 
	 * @param serverName
	 *            服务器名称
	 * @param storePath
	 *            上传文件存储路径
	 * @param fileName
	 *            上传文件存储名称
	 * @param is
	 *            上传文件输入流
	 * @return <b>true</b>：上传成功 <br/>
	 *         <b>false</b>：上传失败
	 */
	public boolean uploadFile(String storePath, String fileName, InputStream is) {
		boolean result = false;
		try {
			// 连接至服务器
			result = connect(storePath);
			// 判断服务器是否连接成功
			if (result) {
				// 上传文件
				result = ftpClient.storeFile(fileName, is);
			}
			// 关闭输入流
			is.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 判断输入流是否存在
			if (null != is) {
				try {
					// 关闭输入流
					is.close();
				} catch (IOException e) {
					logger.error("上传文件至FTP异常" + e.getMessage());
					throw new RuntimeException("上传文件至FTP异常", e);
				}
			}
			// 登出服务器并断开连接
			ftpUtils.logout();
		}
		return result;
	}

	/**
	 * 下载FTP服务器文件至本地<br/>
	 * 操作完成后需调用logout方法与服务器断开连接
	 * 
	 * @param serverName
	 *            服务器名称
	 * @param remotePath
	 *            下载文件存储路径
	 * @param fileName
	 *            下载文件存储名称
	 * @return <b>InputStream</b>：文件输入流
	 */
	public InputStream retrieveFile(String remotePath, String fileName) {
		try {
			boolean result = false;
			// 连接至服务器
			result = connect(remotePath);
			// 判断服务器是否连接成功
			if (result) {
				// 获取文件输入流
				is = ftpClient.retrieveFileStream(fileName);
			}
		} catch (IOException e) {
			logger.error("从FTP下载文件到本地异常" + e.getMessage());
			throw new RuntimeException("从FTP下载文件到本地异常", e);
		}
		return is;
	}

	/**
	 * Description: 从FTP服务器下载文件
	 * 
	 * 
	 * @param remotePath
	 *            FTP服务器上的相对路径
	 * @param fileName
	 *            要下载的文件名
	 * @param localPath
	 *            下载后保存到本地的路径
	 * @return
	 */
	public boolean downFile(String remotePath, String fileName, String localPath) {
		// 初始表示下载失败
		boolean success = false;
		// 表示是否连接成功
		boolean result = false;
		File file = new File(localPath);
		if (!file.exists()) {
			file.mkdirs();
		}
		try {
			// 连接至服务器
			result = connect(remotePath);
			if (result) {
				// 列出该目录下所有文件
				FTPFile[] fs = ftpClient.listFiles();
				// 遍历所有文件，找到指定的文件
				for (FTPFile ff : fs) {
					if (ff.getName().equals(fileName)) {
						// 根据绝对路径初始化文件
						File localFile = new File(localPath + "/" + ff.getName());
						// 输出流
						OutputStream is = new FileOutputStream(localFile);
						// 下载文件
						success = ftpClient.retrieveFile(ff.getName(), is);
						is.close();
					}
				}
			}

		} catch (IOException e) {
			logger.error("从FTP服务器下载文件异常", e);
		} finally {
			// 登出服务器并断开连接
			ftpUtils.logout();
		}
		return success;
	}

	/**
	 * 删除FTP服务器文件
	 * 
	 * @param serverName
	 *            服务器名称
	 * @param remotePath
	 *            当前访问目录
	 * @param fileName
	 *            文件存储名称
	 * @return <b>true</b>：删除成功 <br/>
	 *         <b>false</b>：删除失败
	 */
	public boolean deleteFile(String remotePath, String fileName) {
		boolean result = false;
		// 连接至服务器
		result = connect(remotePath);
		// 判断服务器是否连接成功
		if (result) {
			try {
				// 删除文件
				result = ftpClient.deleteFile(fileName);
			} catch (IOException e) {
				logger.error("删除FTP服务器上的 文件异常" + e.getMessage());
				throw new RuntimeException("删除FTP服务器上的 文件异常", e);
			} finally {
				// 登出服务器并断开连接
				ftpUtils.logout();
			}
		}
		return result;
	}

	/**
	 * 检测FTP服务器文件是否存在
	 * 
	 * @param serverName
	 *            服务器名称
	 * @param remotePath
	 *            检测文件存储路径
	 * @param fileName
	 *            检测文件存储名称
	 * @return <b>true</b>：文件存在 <br/>
	 *         <b>false</b>：文件不存在
	 */
	public boolean checkFile(String remotePath, String fileName) {
		boolean result = false;
		try {
			// 连接至服务器
			result = connect(remotePath);
			// 判断服务器是否连接成功
			if (result) {
				// 默认文件不存在
				result = false;
				// 获取文件操作目录下所有文件名称
				String[] remoteNames = ftpClient.listNames();
				// 循环比对文件名称，判断是否含有当前要下载的文件名
				for (String remoteName : remoteNames) {
					if (fileName.equals(remoteName)) {
						result = true;
					}
				}
			}
		} catch (IOException e) {
			logger.error("检查FTP文件是否存在异常" + e.getMessage());
			throw new RuntimeException("检查FTP文件是否存在异常", e);
		} finally {
			// 登出服务器并断开连接
			ftpUtils.logout();
		}
		return result;
	}

	/**
	 * 登出服务器并断开连接
	 * 
	 * @param ftp
	 *            FTPClient对象实例
	 * @return <b>true</b>：操作成功 <br/>
	 *         <b>false</b>：操作失败
	 */
	public boolean logout() {
		boolean result = false;
		if (null != is) {
			try {
				// 关闭输入流
				is.close();
			} catch (IOException e) {
				logger.error("登录FTP服务器异常" + e.getMessage());
				throw new RuntimeException("登录FTP服务器异常", e);
			}
		}
		if (null != ftpClient) {
			try {
				// 登出服务器
				result = ftpClient.logout();
			} catch (IOException e) {
				logger.error("登录FTP服务器异常" + e.getMessage());
				throw new RuntimeException("登录FTP服务器异常", e);
			} finally {
				// 判断连接是否存在
				if (ftpClient.isConnected()) {
					try {
						// 断开连接
						ftpClient.disconnect();
					} catch (IOException e) {
						logger.error("关闭FTP服务器异常" + e.getMessage());
						throw new RuntimeException("关闭FTP服务器异常", e);
					}
				}
			}
		}
		return result;
	}

	/**
	 * Description: 从FTP服务器下载文件
	 * 
	 * @param url
	 *            FTP服务器hostname
	 * @param port
	 *            FTP服务器端口
	 * @param username
	 *            FTP登录账号
	 * @param password
	 *            FTP登录密码
	 * @param remotePath
	 *            FTP服务器上的相对路径
	 * @param fileName
	 *            要下载的文件名
	 * @param localPath
	 *            下载后保存到本地的路径
	 * @return
	 */
	public static boolean downFile(String url, int port, String username, String password, String remotePath,
			String fileName, String localPath) {
		// 初始表示下载失败
		boolean success = false;
		// 创建FTPClient对象
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			// 连接FTP服务器
			// 如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
			ftp.connect(url, port);
			reply = ftp.getReplyCode();
			/*
			 * 判断是否连接成功
			 */
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return success;
			} else {
				// 登录ftp
				if (ftp.login(username, password)) {
					// 转到指定下载目录
					ftp.changeWorkingDirectory(remotePath);
					// 列出该目录下所有文件
					FTPFile[] fs = ftp.listFiles();
					// 遍历所有文件，找到指定的文件
					for (FTPFile ff : fs) {
						if (ff.getName().equals(fileName)) {
							// 根据绝对路径初始化文件
							File localFile = new File(localPath + "/" + ff.getName());
							// 输出流
							OutputStream is = new FileOutputStream(localFile);
							// 下载文件
							ftp.retrieveFile(ff.getName(), is);
							is.close();
						}
					}
					// 退出ftp
					ftp.logout();
					// 下载成功
					success = true;
				}
			}
		} catch (IOException e) {
			logger.error("从FTP服务器下载文件异常" + e.getMessage());
			throw new RuntimeException("从FTP服务器下载文件异常", e);
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
					logger.error("关闭FTP连接异常" + ioe.getMessage());
					throw new RuntimeException("关闭FTP连接异常", ioe);
				}
			}
		}
		return success;
	}
}